package org.dromara.easyes.core.service;

import org.dromara.easyes.common.utils.CollectionUtils;
import org.dromara.easyes.core.biz.EsPageInfo;
import org.dromara.easyes.core.conditions.select.LambdaEsQueryChainWrapper;
import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper;
import org.dromara.easyes.core.conditions.update.LambdaEsUpdateChainWrapper;
import org.dromara.easyes.core.conditions.update.LambdaEsUpdateWrapper;
import org.dromara.easyes.core.core.BaseEsMapper;
import org.dromara.easyes.core.core.Wrapper;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Optional;

import static org.dromara.easyes.core.toolkit.ResultUtils.retBool;


/**
 * 由 Easy-Es 提供的顶级增强 Service 接口。
 *
 * @author 王帅
 * @since 2.0.0
 * @param <T> 实体类（Entity）类型
 */
@SuppressWarnings("unused")
public interface IService<T> {

    /**
     * 获取对应实体类（Entity）的基础映射类（BaseEsMapper）。
     *
     * @return 基础映射类（BaseEsMapper）
     */
    BaseEsMapper<T> getBaseMapper();

    // ===== 保存（增）操作 =====

    /**
     * 保存实体类对象数据。
     *
     * @param entity 实体类对象
     * @return {@code true} 保存成功，{@code false} 保存失败。
     */
    default boolean save(T entity) {
        return retBool(getBaseMapper().insert(entity));
    }

    /**
     * 保存或者更新实体类对象数据。
     *
     * @param entity 实体类对象
     * @return {@code true} 保存或更新成功，{@code false} 保存或更新失败。
     * @implNote 如果实体类对象主键有值，则更新数据，若没有值，则保存数据。
     * 默认实现是通过反射来进行的，建议根据实际情况自行重写该方法，以提高运行效率。
     */
    boolean saveOrUpdate(T entity);

    /**
     * 批量保存实体类对象数据。
     *
     * @param entityList 实体类对象
     * @return {@code true} 保存成功，{@code false} 保存失败。
     */
    default boolean saveBatch(Collection<T> entityList) {
        return retBool(getBaseMapper().insertBatch(entityList));
    }

    // ===== 删除（删）操作 =====

    /**
     * 根据查询条件删除数据。
     *
     * @param wrapper 查询条件
     * @return {@code true} 删除成功，{@code false} 删除失败。
     */
    default boolean remove(Wrapper<T> wrapper) {
        return retBool(getBaseMapper().delete(wrapper));
    }

    /**
     * 根据数据主键删除数据。
     *
     * @param id 数据主键
     * @return {@code true} 删除成功，{@code false} 删除失败。
     */
    default boolean removeById(Serializable id) {
        return retBool(getBaseMapper().deleteById(id));
    }

    /**
     * 根据数据主键批量删除数据。
     *
     * @param idList 数据主键
     * @return {@code true} 删除成功，{@code false} 删除失败。
     */
    default boolean removeByIds(Collection<? extends Serializable> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            return false;
        }
        return retBool(getBaseMapper().deleteBatchIds(idList));
    }

    // ===== 更新（改）操作 =====

    /**
     * 根据查询条件更新数据。
     *
     * @param entity 实体类对象
     * @param wrapper 查询条件
     * @return {@code true} 更新成功，{@code false} 更新失败。
     */
    default boolean update(T entity, Wrapper<T> wrapper) {
        return retBool(getBaseMapper().update(entity, wrapper));
    }

    /**
     * 根据数据主键更新数据。
     *
     * @param entity 实体类对象
     * @return {@code true} 更新成功，{@code false} 更新失败。
     */
    default boolean updateById(T entity) {
        return retBool(getBaseMapper().updateById(entity));
    }

    /**
     * 根据数据主键批量更新数据。
     *
     * @param entityList 实体类对象
     * @return {@code true} 更新成功，{@code false} 更新失败。
     */
    default boolean updateBatchByIds(Collection<T> entityList) {
        return retBool(getBaseMapper().updateBatchByIds(entityList));
    }

    // ===== 查询（查）操作 =====

    /**
     * 根据数据主键查询一条数据。
     *
     * @param id 数据主键
     * @return 查询结果数据
     */
    default T getById(Serializable id) {
        return getBaseMapper().selectById(id);
    }

    /**
     * 根据数据主键查询一条数据。
     *
     * @param id 数据主键
     * @return 查询结果数据
     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回，方便链式操作。
     */
    default Optional<T> getByIdOpt(Serializable id) {
        return Optional.ofNullable(getById(id));
    }

    /**
     * 根据查询条件查询一条数据。
     *
     * @param wrapper 查询条件
     * @return 查询结果数据
     */
    default T getOne(Wrapper<T> wrapper) {
        return getBaseMapper().selectOne(wrapper);
    }

    /**
     * 根据查询条件查询一条数据。
     *
     * @param wrapper 查询条件
     * @return 查询结果数据
     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回，方便链式操作。
     */
    default Optional<T> getOneOpt(Wrapper<T> wrapper) {
        return Optional.ofNullable(getOne(wrapper));
    }

    /**
     * 查询所有数据。
     *
     * @return 所有数据
     */
    default List<T> list() {
        return list(lambdaQuery());
    }

    /**
     * 根据查询条件查询数据集合。
     *
     * @param wrapper 查询条件
     * @return 数据集合
     */
    default List<T> list(Wrapper<T> wrapper) {
        return getBaseMapper().selectList(wrapper);
    }

    /**
     * 根据数据主键查询数据集合。
     *
     * @param idList 数据主键
     * @return 数据集合
     */
    default List<T> listByIds(Collection<? extends Serializable> idList) {
        return getBaseMapper().selectBatchIds(idList);
    }

    // ===== 数量查询操作 =====

    /**
     * 根据查询条件判断数据是否存在。
     *
     * @param wrapper 包装器
     * @return {@code true} 数据存在，{@code false} 数据不存在
     */
    default boolean exists(Wrapper<T> wrapper) {
        return retBool(count(wrapper));
    }

    /**
     * 查询所有数据数量。
     *
     * @return 所有数据数量
     */
    default Long count() {
        return count(lambdaQuery());
    }

    /**
     * 根据查询条件查询数据数量。
     *
     * @param wrapper 查询条件
     * @return 数据数量
     */
    default Long count(Wrapper<T> wrapper) {
        return getBaseMapper().selectCount(wrapper);
    }

    // ===== 分页查询操作 =====

    /**
     * 分页查询所有数据。
     *
     * @param pageNum 当前页码
     * @param pageSize 每页数据条数
     * @return 分页对象
     */
    default EsPageInfo<T> page(int pageNum, int pageSize) {
        return page(lambdaQuery(), pageNum, pageSize);
    }

    /**
     * 根据查询条件分页查询数据。
     *
     * @param wrapper 查询条件
     * @param pageNum 当前页码
     * @param pageSize 每页数据条数
     * @return 分页对象
     */
    default EsPageInfo<T> page(Wrapper<T> wrapper, int pageNum, int pageSize) {
        return getBaseMapper().pageQuery(wrapper, pageNum, pageSize);
    }

    /**
     * 返回 {@link LambdaEsQueryWrapper} 用于构建搜索查询参数。
     *
     * @return {@link LambdaEsQueryWrapper} 对象
     */
    default LambdaEsQueryWrapper<T> lambdaQuery() {
        return new LambdaEsQueryWrapper<>();
    }

    /**
     * 返回 {@link LambdaEsUpdateWrapper} 用于构建更新查询参数。
     *
     * @return {@link LambdaEsUpdateWrapper} 对象
     */
    default LambdaEsUpdateWrapper<T> lambdaUpdate() {
        return new LambdaEsUpdateWrapper<>();
    }

    /**
     * 返回 {@link LambdaEsQueryChainWrapper} 用于构建链式搜索查询参数。
     *
     * @return {@link LambdaEsQueryChainWrapper} 对象
     */
    default LambdaEsQueryChainWrapper<T> lambdaChainQuery() {
        return new LambdaEsQueryChainWrapper<>(getBaseMapper());
    }

    /**
     * 返回 {@link LambdaEsUpdateChainWrapper} 用于构建链式更新查询参数。
     *
     * @return {@link LambdaEsUpdateChainWrapper} 对象
     */
    default LambdaEsUpdateChainWrapper<T> lambdaChainUpdate() {
        return new LambdaEsUpdateChainWrapper<>(getBaseMapper());
    }

}